﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Pixysoft
{
    public class ByteCoder
    {
        private const byte default_blank = 32;

        private const byte default_tab = 9;

        private const byte default_enter = 13;

        private const byte default_enter2 = 10;

        private static volatile ByteCoder instance;

        private static object syncRoot = new Object();

        public static ByteCoder Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (syncRoot)
                    {
                        instance = new ByteCoder();
                    }
                }

                return instance;

            }
        }


        public byte[] Join(byte[] parent, byte[] value)
        {
            if (parent == null || parent.Length == 0)
                return value;

            if (value == null || value.Length == 0)
                return parent;

            byte[] result = new byte[parent.Length + value.Length];

            parent.CopyTo(result, 0);

            value.CopyTo(result, parent.Length);

            return result;
        }

        public int IndexOf(byte[] buffer, byte breaker)
        {
            if (buffer == null)
                return -1;

            int counter = 0;

            foreach (byte key in buffer)
            {
                if (key == breaker)
                    return counter;

                counter++;
            }

            return -1;
        }

        public byte[] SubBytes(byte[] buffer, int index)
        {
            if (buffer == null)
                return buffer;

            if (index > buffer.Length - 1)
                return new byte[] { };

            if (index < 0)
                return buffer;

            ByteBuilder builder = new ByteBuilder();

            for (int i = index; i < buffer.Length; i++)
            {
                builder.Append(buffer[i]);
            }

            return builder.ToByte();
        }

        public byte[] SubBytes(byte[] buffer, int index, int length)
        {
            if (buffer == null)
                return buffer;

            if (index > buffer.Length - 1)
                return new byte[] { };

            if (index < 0)
                return buffer;

            ByteBuilder builder = new ByteBuilder();

            int counter = 0;

            for (int i = index; i < buffer.Length; i++)
            {
                builder.Append(buffer[i]);

                counter++;

                if (counter > length - 1)
                    break;
            }

            return builder.ToByte();
        }

        public byte[][] Split(byte[] buffer, byte breaker)
        {
            return Split(buffer, breaker, false);
        }

        public byte[][] Split(byte[] buffer, char breaker)
        {
            return Split(buffer, (byte)breaker, false);
        }

        public byte[][] Split(byte[] buffer, char breaker, bool removeEmptyEntries)
        {
            return Split(buffer, (byte)breaker, removeEmptyEntries);
        }

        public byte[][] Split(byte[] buffer, byte breaker, bool removeEmptyEntries)
        {
            List<byte[]> list = new List<byte[]>();

            if (buffer == null)
            {
                list.Add(buffer);

                return list.ToArray();
            }

            ByteBuilder builder = new ByteBuilder();

            foreach (byte key in buffer)
            {
                if (key == breaker)
                {
                    byte[] piece = builder.ToByte();

                    if (!removeEmptyEntries)
                    {
                        list.Add(piece);
                    }
                    else
                    {
                        byte[] rpiece = Trim(piece);

                        if (rpiece == null)
                        {
                            // do nothing
                        }
                        else if (rpiece.Length == 0)
                        {
                            // do nothing
                        }
                        else
                        {
                            list.Add(rpiece);
                        }
                    }

                    builder = new ByteBuilder();
                }
                else
                {
                    builder.Append(key);
                }
            }

            if (builder.Length > 0)
                list.Add(builder.ToByte());

            //if (list.Count == 0)
            //    list.Add(new byte[] { });

            return list.ToArray();
        }

        public byte[] Trim(byte[] buffer)
        {
            if (buffer == null)
                return buffer;

            ByteBuilder builder = new ByteBuilder();

            ByteBuilder checker = new ByteBuilder();

            foreach (byte key in buffer)
            {
                if (key == default_blank || key == 0 || key == default_enter || key == default_enter2 || key == default_tab)//\0
                {
                    checker.Append(key);
                }
                else
                {
                    if (checker.Length > 0 && builder.Length > 0)
                    {
                        builder.Append(checker.ToByte());

                        checker = new ByteBuilder();
                    }

                    builder.Append(key);

                    if (checker.Length > 0)
                    {
                        checker = new ByteBuilder();
                    }
                }
            }

            return builder.ToByte();
        }

        public bool StartWith(byte[] buffer, byte[] value)
        {
            if (buffer == null)
                return false;

            if (value == null)
                return false;

            for (int i = 0; i < value.Length; i++)
            {
                if (buffer[i] != value[i])
                    return false;
            }

            return true;
        }

        public bool EndWith(byte[] buffer, byte[] value)
        {
            if (buffer == null)
                return false;

            if (value == null)
                return false;

            if (buffer.Length == 0)
                return false;

            if (value.Length == 0)
                return false;

            int endindex = GetEndIndex(buffer);

            if (endindex + 1 < value.Length)
                return false;

            for (int i = value.Length - 1; i >= 0; i--)
            {
                if (buffer[endindex + 1 - value.Length + i] != value[i])
                    return false;
            }

            return true;
        }

        /// <summary>
        /// 切割byte
        /// </summary>
        /// <param name="tables"></param>
        /// <returns></returns>
        public byte[][] Devide(byte[] buffer, int maxLength)
        {
            if (buffer == null || buffer.Length == 0)
                return new byte[][] { buffer };

            List<byte[]> devides = new List<byte[]>();

            ByteBuilder builder = new ByteBuilder();

            for (int i = 0; i < buffer.Length; i++)
            {
                builder.Append(buffer[i]);

                if ((i + 1) % maxLength == 0)
                {
                    devides.Add(builder.ToByte());

                    builder = new ByteBuilder();
                }
            }

            if (builder.Length > 0)
                devides.Add(builder.ToByte());

            return devides.ToArray();
        }

        /// <summary>
        /// 指向最后一个非\0的位置Index
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        private int GetEndIndex(byte[] buffer)
        {
            int index = -1;

            if (buffer == null)
                return index;

            for (int i = buffer.Length - 1; i >= 0; i--)
            {
                if (buffer[i] == 0)
                {
                    index = i;
                }
                else
                {
                    break;
                }
            }

            if (index < 0)
                return buffer.Length - 1;
            else
                return index - 1;

        }

        private void test()
        {
            string k1 = "abc";

            byte[] bbb = StringCoder.StringToByte(k1);

            byte[] b1 = SubBytes(bbb, 0, 2);

            byte[] b2 = SubBytes(bbb, 2);

            Console.WriteLine(StringCoder.ByteToString(b1));

            Console.WriteLine(StringCoder.ByteToString(b2));
        }
    }
}
